#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h> 
#include <stdlib.h>       
#include <string.h>
#include <pthread.h>
//#include <sys/sem.h>
#include <errno.h>
#include <sys/ipc.h>
//#include <sys/msg.h>
#include <sys/timeb.h>
#include <sys/socket.h>
//#include <sys/socketvar.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <semaphore.h>
#include <string.h>
#include <termios.h>
#include <linux/input.h>
#include <semaphore.h>
#include <linux/shm.h>
#include <asm/unistd.h>
#include <sys/poll.h>
#include <dirent.h>

#include "common.h"

int bExit = 0;
SystemParam *pgSystemParam = NULL;
pthread_mutex_t projector_WirelessMic_ttyS_Lock;

int iMulti = 1;
static char deviceid[256];
static char devicePassWord[256] = "123456";

static int nFrameRate = 20;
static int nBitRate   = 100000; 

int GetDeviceID();
int is_single_proc_inst_running(const char *process_name);
int loadParam();
void getDeviceIdAndPassWordInfo(char *id, unsigned char &idLen, char *passwd, char &passwdLen);
static void deleteOldLogFile();

int main(int argc, char **argv)
{
		pid_t npid;
		struct sigaction sigact; 	
				
		if( ( npid = fork() ) == -1 )
		{
				printf("fork failure {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;		
		}			
		
		if( npid > 0 )
		{
				return -1;	
		}	

		if( !is_single_proc_inst_running("Terminal") )	
		{
				printf("Terminal running {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;		
		}					
				
		memset(deviceid,0x00,256);	
		GetDeviceID();	

		sigact.sa_handler = UserHandle;
		sigemptyset(&sigact.sa_mask);
		sigact.sa_flags = 0;
		sigaction(SIGINT , &sigact, 0);
		sigaction(SIGTERM, &sigact, 0);
		sigaction(SIGQUIT, &sigact, 0); 	
		sigaction(SIGKILL, &sigact, 0);	
		sigaction(SIGUSR1, &sigact, 0);	
		sigaction(SIGUSR2, &sigact, 0);	
		sigaction(SIGPIPE, &sigact, 0);		
		signal(SIGCHLD, SIG_IGN);
		
		if( ( pgSystemParam = (SystemParam *)malloc(sizeof(SystemParam)) ) == NULL )	
		{
				printf("pgSystemParam malloc fail {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}	
		memset(pgSystemParam, 0, sizeof(SystemParam));		
				
		deleteOldLogFile();
		
		int ret;
		ret = loadParam();
		if(ret != 0)
		{	
				printf("loadParam error ! ret = %d, {%s.%d}\n", ret, __FILE__,__LINE__);
				return -1;
		}
		
		if( InitWirelessMicInput() != 0 )
		{
				printf("InitWirelessMicInput {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( initGpioServer() != 0 )
		{
				printf("initGpioServer {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( initSerialServer() != 0 )
		{
				printf("initGpioServer {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( initScreenVideoSource() != 0 )
		{
				printf("initScreenVideoSource {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( initMonitorAudioVideoServer() != 0 )
		{
				printf("initMonitorAudioVideoServer {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( initMicroClassAudioVideoServer() != 0 )
		{
				printf("initMicroClassAudioVideoServer {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( initPushVideoServer() != 0 )
		{
				printf("initPushVideoServer {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( initFileServer() != 0 )
		{
				printf("initFileServer {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
	
		
		if(initFaad() != 0)
		{
				writeLog("initFaad fail ! \n", __FILE__, __LINE__);
				return -1;	
		}
		
		if(initPushAudioServer() != 0)
		{
				writeLog("initPushAudioServer fail ! \n", __FILE__, __LINE__);
				return -1;	
		}
		
		/*if( initAudioEncoder() != 0 )
		{
				printf("initAudioSource {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( InitSavesvr(&(pgSystemParam->TeacherSave),"teacher",&iMulti) != 0 )
		{
				printf("initAudioSource {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		if( InitSavesvr(&(pgSystemParam->StudentSave),"student",&iMulti) != 0 )
		{
				printf("initAudioSource {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}*/
		
		if(tcpClientInit() != 0)
		{
				writeLog("tcpClientInit fail ! \n", __FILE__, __LINE__);
				return -1;	
		}
		
		if(initSerialACServer() != 0)
		{
				writeLog("initSerialACServer fail ! \n", __FILE__, __LINE__);
				return -1;	
		}

		internalCaptureData *pICplay      = createInternalTask(9100,NULL,1000,audioPlay);
		internalCaptureData *pICmic       = createInternalTask(9200,"/system/bin/micrecord",1000,audioMic);
		internalCaptureData *pICscreen    = createInternalTask(9300,"/system/bin/screenrecord",1000,screenCap);
		internalCaptureData *pICapp2cloud = createInternalTask(9400,NULL,1000,app2Cloud);
		internalCaptureData *pICcompose   = createInternalTask(8600,NULL,1000,composeCap);
		
		if( pICplay == NULL || pICmic == NULL || pICscreen == NULL || pICapp2cloud == NULL || pICcompose == NULL )
		{
				printf("createInternalTask {%s(%d)}",__FILE__,__LINE__);	
				return -1;	
		}
		
		internalCaptureData *pIR					= createInternalTask(8500,NULL,1000,irDeal);
		if( pIR == NULL)
		{
			printf("createInternalTask {%s(%d)}",__FILE__,__LINE__);	
			return -10;	
		}

		initNotify();//input monitoring
		initCompose();
		
		initWifi();
		
		MainServer();

		sleep(2);
		
		system("rm -rf /data/edu/Terminal.lock");
		
		return 0;
}

void UserHandle(int arg)
{		
		printf("kill procecss ! arg = %d\n", arg);
		if( SIGTERM == arg )  
		{
				bExit = 1;
		}
}

int IsExit()
{
		return bExit;
}

extern "C" int IsExitC()
{
		return bExit;
}


int GetDeviceID()
{
		int fd,ret;
		char buf[4096];
		const char *pFlag;
		char *pTmp1;
		char *pTmp2;
		
		if( ( fd = open("/proc/cpuinfo",O_RDONLY) ) == -1 )
		{
				printf("open /proc/cpuinfo error\n");
				return -1;	
		}
		
		if( ( ret = read(fd,buf,4095) ) <= 0 )
		{
				printf("read /proc/cpuinfo error\n");
				close(fd);
				return -1;	
		}
		
		buf[ret] = '\0';
		pFlag = "Serial		: ";
		
		if( ( pTmp1 = strstr(buf,pFlag) ) == NULL )
		{
				printf("Serial error(%d)\n",__LINE__);
				close(fd);
				return -1;	
		}
		
		pTmp1 += strlen(pFlag);
		
		if( ( pTmp2 = strstr(pTmp1,"\r") ) == NULL )
		{
				if( ( pTmp2 = strstr(pTmp1,"\n") ) == NULL )
				{			
						printf("Serial error(%d)\n",__LINE__);
						close(fd);
						return -1;	
				}
		}		
				
		memcpy(deviceid,pTmp1,pTmp2-pTmp1);
		
		close(fd);

		return 0;
}

void getDeviceIdAndPassWordInfo(char **id, unsigned char &idLen, char **passwd, unsigned char &passwdLen)
{
		*id = deviceid;
		idLen = strlen((char*)deviceid);
		*passwd = devicePassWord;
		passwdLen = strlen((char*)devicePassWord);
}

int GetFrameRate()
{
		return nFrameRate;
}

int GetBitRate()
{
		return nBitRate;
}

static int g_single_proc_inst_lock_fd = -1;

static void single_proc_inst_lockfile_cleanup(void)
{
    if (g_single_proc_inst_lock_fd != -1) {
        close(g_single_proc_inst_lock_fd);
        g_single_proc_inst_lock_fd = -1;
    }
}

int is_single_proc_inst_running(const char *process_name)
{
    char lock_file[128];
    snprintf(lock_file, sizeof(lock_file), "/data/edu/%s.lock", process_name);

    g_single_proc_inst_lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
    if (-1 == g_single_proc_inst_lock_fd) {
        fprintf(stderr, "Fail to open lock file(%s). Error: %s\n",
            lock_file, strerror(errno));
        return 0;
    }

    if (0 == flock(g_single_proc_inst_lock_fd, LOCK_EX | LOCK_NB)) {
        atexit(single_proc_inst_lockfile_cleanup);
        return 1;
    }

    close(g_single_proc_inst_lock_fd);
    g_single_proc_inst_lock_fd = -1;
    return 0;

}

int loadParam()
{	
		const char saveDir[80] = "/sdcard/mp4";
		memcpy(pgSystemParam->cSaveDir, saveDir, strlen(saveDir));
		
		//const char deviceName[80] = "incastCloudTerminal";
		//memcpy(pgSystemParam->deviceName, deviceName, strlen(deviceName));
		
		if( InitBlockInfoBuffer(&(pgSystemParam->pcmComposeBlock),1024,1024*200) != 0 )
		{
				printf("InitBlockInfoBuffer failed {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;			
		}
		
		if( InitBlockInfoBuffer(&(pgSystemParam->aacPushBlock),1024,100*1024) != 0 )
		{
				printf("InitBlockInfoBuffer failed {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;			
		}
		
		if( InitBlockInfoBuffer(&(pgSystemParam->aacMineBlock),1024,100*1024) != 0 )
		{
				printf("InitBlockInfoBuffer failed {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;			
		}

		if( InitBlockInfoBuffer(&(pgSystemParam->TeacherSave),1024,1024*1024*32) != 0 )
		{
				printf("InitBlockInfoBuffer failed {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;			
		}
		
		if( InitBlockInfoBuffer(&(pgSystemParam->StudentSave),1024,1024*1024*32) != 0 )
		{
				printf("InitBlockInfoBuffer failed {%s(%d)}\n",__FILE__,__LINE__);	
				return -1;			
		}
		
		if( pthread_mutex_init(&projector_WirelessMic_ttyS_Lock, NULL) != 0   ) 
		{
				printf("pthread_mutex_init failure {%s(%d)}\n",__FILE__,__LINE__);	
				return -8;
		}	
		
		pgSystemParam->iSaveInterval = 60;
		
		pgSystemParam->centerCtrlMachineIsOpen = false;
		pgSystemParam->pushingAudio = false;
		
		pgSystemParam->sysRestarting = false;
		
		int ret;
		ret = fixConfigFile(SAVE_CONFIG_DIR,CONFIG_DIR, SAVE_CONFIG2_DIR,CONFIG2_DIR);
		if(ret < 0)
		{
				printf("combineConfigFile fail ! ret = %d\n", ret);
				return -4;
		}
		
		ret = readConfigFile(CONFIG_DIR);
		if(ret < 0)
		{
			printf("readConfigFile fail ! ret = %d\n", ret);

			char cmd[256];
			snprintf(cmd, 256, "mv %s %s", CONFIG_DIR, SAVE_CONFIG_DIR_EX);
			system(cmd);

			if (access(SAVE_CONFIG_DIR, F_OK) != 0)
			{
				system("wget http://update.incastyun.cn:2680/terminal.config -P /data/edu");
			}
			else
			{
				snprintf(cmd, 256, "mv %s %s", SAVE_CONFIG_DIR, CONFIG_DIR);
				system(cmd);
			}
			system("chmod 777 /data/edu/terminal.config");
			system("reboot");

			return -1;
		}
		
		//char value[99];
		//readOneConfigValue(SOFTWARE_VERSION_KEY, value);
		
		/*ret = writeSoftwareVersionToCfg(SOFTWARE_VERSION_VALUE);
		if(ret < 0)
		{
				printf("writeSoftwareVersionToCfg fail ! ret = %d\n", ret);
				return -2;	
		}*/

		ret = initOther();
		if(ret < 0)
		{
				printf("initOther fail ! ret = %d\n", ret);
				return -3;	
		}

		return 0; 
		
}

static void deleteOldLogFile()
{
		static const unsigned int keepDays = 14;
		static const char defaultLogdir[] = "/data/edu/log";
		char fileName[256] = {0};
		
		time_t tt;
		time(&tt);
		//printf("tt = %u\n", tt);
		tt -= (keepDays + 0) * 24 * 60 * 60;
		//printf("tt = %u\n", tt);
		struct tm *tim = localtime(&tt);
		
		//sprintf(fileName, "%s/ulog.%04d%02d%02d",defaultLogdir,1900+tim->tm_year,tim->tm_mon+1,tim->tm_mday);
		sprintf(fileName, "ulog.%04d%02d%02d", 1900+tim->tm_year,tim->tm_mon+1,tim->tm_mday);
		printf("fileName = %s\n", fileName);
		
		struct dirent *entry;
		DIR *dirptr = NULL;
		dirptr = opendir(defaultLogdir);
		if(!dirptr) return;
			
		char cmd[256];
		while(entry = readdir(dirptr))
		{
				printf("entry->d_name = %s\n", entry->d_name);
				if(strstr(entry->d_name, "ulog."))
				{
						if(strcmp(entry->d_name, fileName) < 0)
						{
								sprintf(cmd, "rm -rf %s/%s", defaultLogdir,entry->d_name);	
								printf("cmd = %s\n", cmd);
								system(cmd);
						}
				}
		}
}
